﻿namespace Resharper.Abstractions.CodeDom
{
  using System;
  using JetBrains.Annotations;
  using JetBrains.ReSharper.Psi;
  using JetBrains.ReSharper.Psi.Util;

  /// <summary>Defines the <see cref="Type"/> class.</summary>
  public class Type
  {
    /// <summary>The language field.</summary>
    private readonly PsiLanguageType languageType;

    #region Constructors and Destructors

    /// <summary>Initializes a new instance of the <see cref="Type"/> class.</summary>
    /// <param name="type">The type.</param>
    /// <param name="languageType">Type of the language.</param>
    internal Type([NotNull] IType type, [NotNull] PsiLanguageType languageType)
    {
      if (type == null)
      {
        throw new ArgumentNullException("type");
      }

      if (languageType == null)
      {
        throw new ArgumentNullException("languageType");
      }

      this.InternalType = type;
      this.languageType = languageType;
    }

    #endregion

    #region Properties

    /// <summary>
    /// Gets a value indicating whether this instance is reference type.
    /// </summary>
    public bool IsReferenceType
    {
      get
      {
        return this.InternalType.IsReferenceType();
      }
    }

    /// <summary>
    /// Gets a value indicating whether this instance is enumerable.
    /// </summary>
    public bool IsEnumerable
    {
      get
      {
        var enumerable = TypeFactory.CreateTypeByCLRName("System.Collections.IEnumerable", this.InternalType.Module);
       return this.InternalType.IsSubtypeOf(enumerable);
      }
    }

    /// <summary>
    /// Gets a value indicating whether this instance is void.
    /// </summary>
    public bool IsVoid
    {
      get
      {
        return this.InternalType.IsVoid();
      }
    }

    /// <summary>Returns a <see cref="System.String"/> that represents this instance.</summary>
    /// <returns>A <see cref="System.String"/> that represents this instance.</returns>
    public override string ToString()
    {
      return this.InternalType.GetPresentableName(this.languageType);
    }

    /// <summary>
    /// Gets or sets the type.
    /// </summary>
    /// <value>The type.</value>
    internal IType InternalType { get; set; }

    #endregion
  }
}